# sim/sim_runner.py

import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, FallingEdge, Timer
import os
import json
import random
import argparse
from pathlib import Path

def main():
    parser = argparse.ArgumentParser(description="Cocotb 仿真运行器")
    parser.add_argument("--config", required=True, help="JSON 配置文件")
    args = parser.parse_args()
    
    # 加载配置
    with open(args.config, "r") as f:
        config = json.load(f)
    
    # 运行仿真
    run_simulation(config)

@cocotb.test()
async def run_simulation(config: dict):
    """主仿真函数"""
    # 获取 DUT
    if "dut" in cocotb.top.__dict__:
        dut = cocotb.top.dut
    else:
        dut = cocotb.top
        
    print(f"Starting simulation with config: {config}")
    
    # 从配置中获取参数
    duration = config.get("duration", 50)
    targets = config.get("targets", [])
    wave_file = config.get("wave_file", "dump.vcd")
    
    # 启用波形
    if wave_file:
        cocotb.start_soon(cocotb.utils.set_simulator_waveform(wave_file, vcd=True))
    
    # 创建时钟
    clock_period = config.get("clock_period", 20)  # ns
    clock = Clock(dut.clk, clock_period, units="ns")
    cocotb.start_soon(clock.start())
    
    # 初始化信号
    dut.rst_n.value = 0
    dut.en.value = 0
    await Timer(20, units="ns")
    
    # 复位释放
    dut.rst_n.value = 1
    await RisingEdge(dut.clk)
    
    # 主测试逻辑
    expected_cnt = 0
    for cycle in range(duration):
        if targets:
            en_value = generate_targeted_en(targets, cycle)
        else:
            en_value = random.randint(0, 1)
        
        dut.en.value = en_value
        await RisingEdge(dut.clk)
        await FallingEdge(dut.clk)
        
        # 在这里添加您的断言逻辑...
        current_cnt = int(dut.cnt.value)
        print(f"Cycle {cycle}: cnt={current_cnt}, ovf={dut.ovf.value}")
        
        # 检查覆盖率目标
        check_coverage_targets(targets, cycle, dut)
    
    print("Simulation completed successfully")

def generate_targeted_en(targets, cycle):
    """生成针对特定测试目标的使能信号"""
    if "count_overflow" in targets:
        if cycle == 10:
            return 1  # 使能计数
        else:
            return 0
    return random.randint(0, 1)

def check_coverage_targets(targets, cycle, dut):
    """检查覆盖率目标是否达成"""
    if "count_overflow" in targets:
        if cycle == 11 and int(dut.ovf.value) != 1:
            print("ERROR: Overflow flag not set at cycle 11")
            # 记录到日志...

if __name__ == "__main__":
    main()